#include "Molecule.h"
#include "Atom_Element.h"
#include "ModelException.h"
#include "Molecule_Visitor.h"
#include "Fragment_Link_Builder.h"

static void postprocess_fragment(Fragment* frag, Fragment* prev_frag, AtomElementIndexer atom_element_indexer, Molecule* molecule);

Molecule::~Molecule()
{
    for (Atoms::const_iterator i = atoms.begin(); i != atoms.end(); ++i)
    {
        Atom* atom = *i;
        delete atom;
    }
}

void Molecule::add(const Atom& at, const Atom_Element& elm)
{
    // Does it makes sense to read an atom not inside a fragment?
    // Not sure, but just in case we fail fast :)
    if (fragments.size() == 0)
    {
        throw ModelException("Tried to read an atom not inside a fragment.");
    }

    // Save it to the list
    Atom* atom = at.clone();
    atoms.push_back(atom);
    atom_element_indexer.add(atom, elm);

    // Add a reference to this atom in the current fragment
    Fragment& last_fragment = fragments.back();
    last_fragment.add(atom);
}

void Molecule::add_link(const Atom_Link* link)
{
	atom_links.push_back( link );
}

/**
 * Notify this molecule that future atoms should be added as part of a new fragment
 * TODO: Add an observer system and notify each observer that a fragment is now complete so it can be postprocesed
 */
void Molecule::on_fragment_change()
{
    // TODO: Preproc, This should be an observer
    unsigned l = fragments.size();

    if (l == 0)
    {
        // We don't care, there are no fragments read
    }
    else if (l == 1)
    {
        // There is one fragment fully read
        Fragment& frag = fragments[l - 1];
        postprocess_fragment(&frag, NULL, atom_element_indexer, this);
    }
    else if (l > 1)
    {
        Fragment& frag = fragments[l - 1];
        Fragment& prev_frag = fragments[l - 2];
        postprocess_fragment(&frag, &prev_frag, atom_element_indexer, this);
    }

    fragments.push_back(Fragment());
}

/**
 * Order atoms by type and then iterate
 */
void Molecule::iterate_atoms_by_type(Molecule_Visitor& v) const
{
    atom_element_indexer.iterate_atoms_by_type(v);
}

#include <iostream>
#include "Fragment_Matcher.h"
void postprocess_fragment(Fragment* frag, Fragment* prev_frag, AtomElementIndexer atom_element_indexer, Molecule *molecule)
{
    AminoacidMatcher aam(atom_element_indexer);
	 aam.match(frag);
	 std::cout << "Found fragment " << frag->get_name() << " with a sequence " << frag->get_sequence(atom_element_indexer) << "\n";

	 FragmentLinkBuilder flb;
	 flb.build_links( frag, molecule );
}




